package com.lanyus.crack.xmind;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodNode;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.List;

public class Agent {
    public static void premain(String args, Instrumentation inst) {
        inst.addTransformer(new MethodEntryTransformer());
    }

    private static class MethodEntryTransformer implements ClassFileTransformer {

        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
            try {
                if (className != null && className.startsWith("net/xmind/verify/internal/LicenseVerifier")) {
                    ClassReader cr = new ClassReader(classfileBuffer);
                    ClassNode cn = new ClassNode();
                    cr.accept(cn, 0);
                    List<MethodNode> methodNodes = cn.methods;
                    for (MethodNode methodNode : methodNodes) {
                        if ("checkSignatureValid".equals(methodNode.name) || "doCheckLicenseKeyBlacklisted".equals(methodNode.name)) {
                            Type[] type = Type.getArgumentTypes(methodNode.desc);
                            Type returnType = Type.getReturnType(methodNode.desc);
                            if (("checkSignatureValid".equals(methodNode.name) && type.length == 3 || "doCheckLicenseKeyBlacklisted".equals(methodNode.name) && type.length == 2) && returnType.toString().equals("Z")) {
                                InsnList insnList = methodNode.instructions;
                                insnList.clear();
                                insnList.add(new InsnNode(Opcodes.ICONST_1));
                                insnList.add(new InsnNode(Opcodes.IRETURN));
                                methodNode.exceptions.clear();
                                methodNode.visitEnd();
                                ClassWriter cw = new ClassWriter(0);
                                cn.accept(cw);
                                System.out.println(className + " -> " + methodNode.name + " -> " + methodNode.desc);
                                return cw.toByteArray();
                            }
                        }
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
            return classfileBuffer;
        }
    }
}
